package han.Chensing.CibMidi;

import han.Chensing.CibMidi.raw.MidiChunk;
import han.Chensing.CibMidi.raw.MidiDataRaw;
import han.Chensing.CibMidi.raw.MidiEvent;
import han.Chensing.CibMidi.util.StreamUtil;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class MidiData {
    private final List<MidiTrack> tracks;
    private final MidiBasicInfo midiBasicInfo;
    MidiData(){
        this.tracks=new ArrayList<>();
        this.midiBasicInfo=new MidiBasicInfo();
    }

    public List<MidiTrack> getTracks() {
        return tracks;
    }

    public static MidiData formRawData(MidiDataRaw raw) throws IOException {
        MidiData midiData=new MidiData();
        List<MidiTrack> tracks = midiData.getTracks();
        int trackNum = getTrackNum(raw);
        for(int i=0;i<trackNum;i++){
            MidiTrack e = new MidiTrack();
            e.setNum(i);
            tracks.add(e);
        }
        List<MidiChunk> chunks = raw.getChunks();
        for(MidiChunk chunk:chunks){
            List<MidiEvent> events = chunk.getEvents();
            for(MidiEvent event:events){
                int track = event.getTrack();
                if (track>=0) {
                    MidiTrack midiTrack = tracks.get(track);
                    midiTrack.setDuration(midiTrack.getDuration() + event.getDeltaTime());
                    midiTrack.getEvents()
                            .add(event);
                    continue;
                }
                if (event.getEventType()!= MidiEvent.EventType.Other)
                    continue;
                Object[] parameters = event.getParameters();
                if (parameters.length!=2)
                    continue;
                int parameter = (int) parameters[0];
                //noinspection SwitchStatementWithTooFewBranches
                switch (parameter){
                    case MidiBasicInfo.microsecondPerQuarterNoteCode:
                        byte[] parameter1 = (byte[]) parameters[1];
                        byte[] bytes=new byte[]{0x00,parameter1[0],parameter1[1],parameter1[2]};
                        ByteArrayInputStream byteArrayInputStream=new ByteArrayInputStream(bytes);
                        midiData.midiBasicInfo.microsecondPerQuarterNote= StreamUtil.readInt32(byteArrayInputStream);
                        byteArrayInputStream.close();
                        break;
                }
            }
        }
        return midiData;
    }

    private static int getTrackNum(MidiDataRaw raw){
        HashSet<Integer> hashSet=new HashSet<>();
        List<MidiChunk> chunks = raw.getChunks();
        for(MidiChunk chunk:chunks){
            List<MidiEvent> events = chunk.getEvents();
            for (MidiEvent event:events){
                int track = event.getTrack();
                hashSet.add(track);
            }
        }
        return hashSet.size();
    }

    public MidiBasicInfo getMidiBasicInfo() {
        return midiBasicInfo;
    }
}
